﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Runtime.Serialization;
using System.Xml.Serialization;
using System.IO;

namespace Wpf3D
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        System.Windows.Threading.DispatcherTimer frameTimer = new System.Windows.Threading.DispatcherTimer();
        public Window1()
        {
            InitializeComponent();
            LoadBuildings();
            //SaveToFile();
            frameTimer.Interval = TimeSpan.FromSeconds(1 / 30.0f);
            frameTimer.IsEnabled = true;
            frameTimer.Tick += new EventHandler(frameTimer_Tick);
            frameTimer.Start();
        }
        float angle = 0;

        void frameTimer_Tick(object sender, EventArgs e)
        {
            angle+=0.05f;
            //System.Diagnostics.Debug.WriteLine(angle.ToString());
            Point3D position = new Point3D(10*(float)Math.Cos(angle),10, 10 * (float)Math.Sin(angle));
            camera.Position = position;
            Vector3D direction = new Vector3D(position.X,position.Y,position.Z);
            direction.Normalize();
            direction *= -1;
            camera.LookDirection = direction;// new Vector3D(-(float)Math.Cos(angle), -10, -(float)Math.Sin(angle));
        }
        AmbientLight ambientLight = new AmbientLight(Colors.White);
        DirectionalLight directionalLight = new DirectionalLight(Colors.White, new Vector3D(-1, -1, -1));
        
        public void LoadBuildings()
        {


            //transform.CenterX = 0.5f;
            //transform.CenterY = 0.5f;
            //transform.Angle = 0;

            XmlSerializer serializer = new XmlSerializer(typeof(List<Building>));
            FileStream stream = File.Open("Buildings.xml", FileMode.Open);
            List<Building> buildings = (List<Building>)serializer.Deserialize(stream);
            stream.Close();
            foreach (Building building in buildings)
            {
                ImageBrush imgBr = new ImageBrush();
                imgBr.ImageSource = new BitmapImage(new Uri(@"Resources\building.png", UriKind.RelativeOrAbsolute));
                RotateTransform transform = new RotateTransform();
                transform.CenterX = 0.5f;
                transform.CenterY = 0.5f;
                transform.Angle = 0;
                imgBr.Transform = transform;

                ModelVisual3D visual3D = new ModelVisual3D();
                Model3DGroup group = new Model3DGroup();
                MeshGeometry3D mesh = new MeshGeometry3D();
                //八顶点
                Point3D[] ps = new Point3D[8];
                ps[0] = new Point3D(building.Position.X - building.Width / 2.0f, 0, building.Position.Y-building.Length / 2.0f);
                ps[1] = new Point3D(building.Position.X + building.Width / 2.0f, 0, building.Position.Y - building.Length / 2.0f);
                ps[2] = new Point3D(building.Position.X + building.Width / 2.0f, 0, building.Position.Y + building.Length / 2.0f);
                ps[3] = new Point3D(building.Position.X - building.Width / 2.0f, 0, building.Position.Y + building.Length / 2.0f);
                for (int i = 0; i < 4; i++)
                {
                    ps[i + 4] = ps[i];
                    ps[i + 4].Y = building.Height;
                }
                //for (int i = 0; i < 8; i++)
                //    mesh.Positions.Add(ps[i]);
            
                Point upperLeft = new Point(1,0);
                Point upperRight = new Point(0,0);
                Point bottomLeft = new Point(1,1);
                Point bottomRight = new Point(0,1);

                int[] indices = new int[30];
                //顺时针方向
                //第一个面
                indices[0] = 0; indices[1] = 4; indices[2] = 1;
                indices[3] = 1; indices[4] = 4; indices[5] = 5;
                //mesh.Positions.Add(ps[0]);
                //mesh.Positions.Add(ps[4]);
                //mesh.Positions.Add(ps[1]);
                //mesh.Positions.Add(ps[1]);
                //mesh.Positions.Add(ps[4]);
                //mesh.Positions.Add(ps[5]);
                for (int i = 0; i < 4; i++)
                {
                    mesh.TextureCoordinates.Add(bottomLeft);
                    mesh.TextureCoordinates.Add(upperLeft);
                    mesh.TextureCoordinates.Add(bottomRight);
                    mesh.TextureCoordinates.Add(bottomRight);
                    mesh.TextureCoordinates.Add(upperLeft);
                    mesh.TextureCoordinates.Add(upperRight);
                }
                //第二个面
                indices[6] = 1; indices[7] = 5; indices[8] = 2;
                indices[9] = 2; indices[10] = 5; indices[11] = 6;
                //mesh.Positions.Add(ps[1]);
                //mesh.Positions.Add(ps[5]);
                //mesh.Positions.Add(ps[6]);
                //mesh.Positions.Add(ps[1]);
                //mesh.Positions.Add(ps[6]);
                //mesh.Positions.Add(ps[2]);
                //mesh.TextureCoordinates.Add(bottomLeft);
                //mesh.TextureCoordinates.Add(upperLeft);
                //mesh.TextureCoordinates.Add(bottomRight);
                //mesh.TextureCoordinates.Add(bottomRight);
                //mesh.TextureCoordinates.Add(upperLeft);
                //mesh.TextureCoordinates.Add(upperRight);

                //第三个面
                indices[12] = 2; indices[13] = 6; indices[14] = 3;
                indices[15] = 3; indices[16] = 6; indices[17] = 7;
                //mesh.Positions.Add(ps[2]);
                //mesh.Positions.Add(ps[6]);
                //mesh.Positions.Add(ps[7]);
                //mesh.Positions.Add(ps[2]);
                //mesh.Positions.Add(ps[7]);
                //mesh.Positions.Add(ps[3]);
                //mesh.TextureCoordinates.Add(bottomLeft);
                //mesh.TextureCoordinates.Add(upperLeft);
                //mesh.TextureCoordinates.Add(bottomRight);
                //mesh.TextureCoordinates.Add(bottomRight);
                //mesh.TextureCoordinates.Add(upperLeft);
                //mesh.TextureCoordinates.Add(upperRight);
                //第四个面
                indices[18] = 3; indices[19] = 7; indices[20] = 0;
                indices[21] = 0; indices[22] = 7; indices[23] = 4;
                //mesh.Positions.Add(ps[3]);
                
                //mesh.TextureCoordinates.Add(bottomLeft);
                //mesh.TextureCoordinates.Add(upperLeft);
                //mesh.TextureCoordinates.Add(bottomRight);
                //mesh.TextureCoordinates.Add(bottomRight);
                //mesh.TextureCoordinates.Add(upperLeft);
                //mesh.TextureCoordinates.Add(upperRight);
                //顶面
                indices[24] = 4; indices[25] = 7; indices[26] = 5;
                indices[27] = 5; indices[28] = 7; indices[29] = 6;
                //mesh.TextureCoordinates.Add(bottomLeft);
                //mesh.TextureCoordinates.Add(upperLeft);
                //mesh.TextureCoordinates.Add(bottomRight);
                //mesh.TextureCoordinates.Add(bottomRight);
                //mesh.TextureCoordinates.Add(upperLeft);
                //mesh.TextureCoordinates.Add(upperRight);
                for (int i = 0; i < 30; i++)
                {
                    mesh.Positions.Add(ps[indices[i]]);
                    mesh.TriangleIndices.Add(i);
                }
                Vector3D negZ = new Vector3D(0, 0, -1);
                Vector3D posZ = new Vector3D(0, 0, 1);
                Vector3D negX = new Vector3D(-1, 0, 0);
                Vector3D posX = new Vector3D(1, 0, 0);
                Vector3D negY = new Vector3D(0, -1, 0);
                Vector3D posY = new Vector3D(0, 1, 0);
                //第一个面六个顶点的法线
                mesh.Normals.Add(negZ);
                mesh.Normals.Add(negZ);
                mesh.Normals.Add(negZ);
                mesh.Normals.Add(negZ);
                mesh.Normals.Add(negZ);
                mesh.Normals.Add(negZ);
                //第二个面六个顶点的法线
                mesh.Normals.Add(posX);
                mesh.Normals.Add(posX);
                mesh.Normals.Add(posX);
                mesh.Normals.Add(posX);
                mesh.Normals.Add(posX);
                mesh.Normals.Add(posX);
                //第三个面六个顶点的法线
                mesh.Normals.Add(posZ);
                mesh.Normals.Add(posZ);
                mesh.Normals.Add(posZ);
                mesh.Normals.Add(posZ);
                mesh.Normals.Add(posZ);
                mesh.Normals.Add(posZ);
                //第四个面六个顶点的法线
                mesh.Normals.Add(negX);
                mesh.Normals.Add(negX);
                mesh.Normals.Add(negX);
                mesh.Normals.Add(negX);
                mesh.Normals.Add(negX);
                mesh.Normals.Add(negX);
                //最顶面
                mesh.Normals.Add(posY);
                mesh.Normals.Add(posY);
                mesh.Normals.Add(posY);
                mesh.Normals.Add(posY);
                mesh.Normals.Add(posY);
                mesh.Normals.Add(posY);


                DiffuseMaterial diffuseMaterial = new DiffuseMaterial();
                diffuseMaterial.AmbientColor = Colors.White;
                //diffuseMaterial.Brush = new SolidColorBrush(Colors.Red);
                diffuseMaterial.Brush = imgBr;
                diffuseMaterial.Color = building.DiffuseColor;
                
                GeometryModel3D model3D = new GeometryModel3D(mesh, diffuseMaterial);
                model3D.BackMaterial = diffuseMaterial;
                model3D.Material = diffuseMaterial;
                model3D.Transform = new ScaleTransform3D(new Vector3D(0.3, 0.3, 0.3));
                WorldModel.Children.Add(model3D);
                //group.Children.Add(diffuseMaterial);
                //group.Children.Add(directionalLight);
                //group.Children.Add(model3D);

                //visual3D.Content = group;
                //World.Children.Add(visual3D);
            }


        }
 
        public void SaveToFile()
        {
            List<Building> buildings = new List<Building>();
            Building b1 = new Building();
            b1.Position = new Point(0, 0);
            b1.Height = 10;
            b1.Width = 5;
            b1.Length = 5;
            b1.DiffuseColor = Colors.SkyBlue;
            Building b2 = new Building();
            b2.Position = new Point(10, 10);
            b2.Height = 15;
            b2.Width = 6;
            b2.Length = 6;
            b2.DiffuseColor = Colors.Green;
            buildings.Add(b1);
            buildings.Add(b2);
            XmlSerializer serializer = new XmlSerializer(typeof(List<Building>));
            FileStream stream = File.Create("Buildings.xml");
            serializer.Serialize(stream, buildings);
            stream.Close();
        }
    }
    [Serializable]
    public class Building
    {
        public Point Position;
        public int Width;
        public int Length;
        public int Height;
        public Color DiffuseColor;
    }
}
